﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Google.Api.Maps.Service.StaticMaps;
using System.Collections;

namespace NextViewer
{
    class Commands
    {
        public Commands(Shell sh)
        {
            map = new StaticMap();
            map.Size = "640x640";
            
            mPoint = new Points();
            shell = sh;
        }
        internal NextViewer mnv;
        public NextViewer Terminal
        {
            set { mnv = value; }
        }

        public void UpdatePic(string input)
        {

            
            string cmd = input.Substring(2);
            string[] cmds = cmd.Split(' ');
            if (cmds[0] == "update")
            {
                for (int i = 1; i < cmds.Length - 1; i += 2)
                {
                    if (cmds[i] == "-u")
                    {
                        user = cmds[i + 1];
                        if (user == "jy")
                            user = "359506045228940";
                        if (user == "cj")
                            user = "358414046179405";
                    }
                    else if (cmds[i] == "-d")
                    {
                    }
                    else if (cmds[i] == "-o")
                    {
                        try
                        {
                            mnv.SetOpacity(double.Parse(cmds[i + 1]));
                        }
                        catch (Exception ee)
                        {
                            mnv.SetText(ee.ToString());
                        }
                    }
                    else if (cmds[i] == "-ps")
                    {
                        try
                        {
                            dtStart = DateTime.Parse(cmds[i + 1] + " " + cmds[i + 2]);
                        }
                        catch (Exception)
                        {
                            mnv.SetText("입력은 : yyyy-mm-dd HH:MM 형태입니다.");
                            return;
                        }
                        i++;
                    }
                    else if (cmds[i] == "-pe")
                    {
                        try
                        {
                            dtEnd = DateTime.Parse(cmds[i + 1] + " " + cmds[i + 2]);
                        }
                        catch (Exception)
                        {
                            mnv.SetText("입력은 : yyyy-mm-dd HH:MM 형태입니다.");
                            return;
                        }
                        i++;
                    }
                    else if (cmds[i] == "-p")
                    {

                    }
                }

                mnv.SetText(map.ToUri().ToString());
            }
            else if (cmds[0] == "run")
            {
                GetRawData();
                UpdatePointsForLocation();
                PrintVelocity();
                MakeHttpRequest();
                mnv.updatePic(map);
                map.InitMarker();

            }
            else if (cmds[0] == "display")
            {
                mnv.updatePic();
                double scale=0.1,trans=0;
                if (cmds.Length > 2)
                {
                    scale = (double.Parse(cmds[1]));
                    trans = (double.Parse(cmds[2]));
                }
                CreateForest();
                double[] s = { scale, scale, scale };
                double[] t = { trans, trans, trans};
                mnv.DrawPoints(s,t,forest);
            }
            else if (cmds[0] == "displayApp")
            {
                mnv.updatePic();
                double scale = 0.1, trans = 0;
                if (cmds.Length > 2)
                {
                    scale = (double.Parse(cmds[1]));
                    trans = (double.Parse(cmds[2]));
                }
                CreateForestApp();
                double[] s = { scale, scale, scale };
                double[] t = { trans, trans, trans };
                mnv.DrawPoints(s, t, forest);
            }
            else if (cmds[0] == "fake")
            {
                List<double[]> list = new List<double[]>();
                List<DateTime> list2 = new List<DateTime>();
                Util.GetFakeGPStable(list,list2);
                for(int i=0;i<list.Count;i++)
                {
                    mnv.SetText("\t"+ list[i][0] + "\t"+ list[i][1] + "\t"+ list[i][2] + "\t"+ list[i][3]+"\t"+list2[i].ToString()); 
                }
            }
            else if (cmds[0] == "dist")
            {
                GetDistributionGPS();
            }
            //nv.SetText("update -u(user) -d(date) -p(path) -ps(period start) -pe(period end) -c(center) -z(zoom) -f(format) -mt(maptype) -mo(mobile) -s(sensor)");


        }
        public void CreateForestApp()
        {
            forest = new Nodes();
            int i = 0;
            for (i = 0; i < mPoint.mPt.Count - 1; i++)
            {
                Pot pt1 = mPoint.mPt[i];
                Pot pt2 = mPoint.mPt[i + 1];

                Edges ed = new Edges();
                ed.Add(pt2.CellID);
                forest.Add(pt1.CellID, pt1.appLon, pt1.appLat, 1, ed);

            }
            Pot fp = mPoint.mPt[i];
            Edges fed = new Edges();
            forest.Add(fp.CellID, fp.Lon, fp.Lat, 1, fed);
        }
        public void CreateForest()
        {
            GetRawData();
            UpdatePointsForLocation();
                
            forest = new Nodes();
            int i=0;
            for (i=0;i<mPoint.mPt.Count-1;i++)
            {
                Pot pt1 = mPoint.mPt[i];
                Pot pt2 = mPoint.mPt[i+1];

                Edges ed = new Edges();
                ed.Add(pt2.CellID);
                forest.Add(pt1.CellID, pt1.Lon,pt1.Lat, 1, ed);
                
            }
            Pot fp = mPoint.mPt[i];
            Edges fed = new Edges();
            forest.Add(fp.CellID, fp.Lon, fp.Lat, 1, fed);
        }
        public void Enviroment(string input)
        {
            string cmd = input.Substring(2);
            string[] cmds = cmd.Split(' ');

            if (cmds[0] == "keep")
            {
                addon += cmd.Substring(5);

            }
            else if (cmds[0] == "addon-clear")
            {
                addon = "";
            }
            else if (cmds[0] == "clear")
            {
                mnv.ClearConsole();
            }
            else if (cmds[0] == "compNet")
            {
                CompareDataSet();
            }
            else if (cmds[0] == "networkGap")
            {
                if(cmds.Length > 1)
                    Glovar.networkGap = double.Parse(cmds[1]);
            }
            else if (cmds[0] == "spot")
            {
                RouteManager rt = new RouteManager(shell);
                //user = "359506045228940";
                rt.id = user;
                rt.Analysis();
            }
            else if (cmds[0] == "cl")
            {
                Clustering cl = new Clustering(this);
                cl.Threathold();
            }
            else if (cmds[0] == "test")
            {
                Points pt = Util.GetGPSPointPair(DateTime.Parse(cmds[1] + " " + cmds[2]),
                    DateTime.Parse(cmds[3] + " " + cmds[4]), cmds[5]);
            }
            mnv.SetText(cmd);
        }

        public void GetRawData()
        {
            mPoint.mPt.Clear();
            string format = "yyyy-MM-dd HH:mm";
            string query = @"SELECT TIME, WIFI, BRIGHTNESS, BLUETOOTH, SOUND, GPS, LOC_LAT, LOC_LON, ID, APP, HEADSET, PLUGGED, LOC_ACCURACY, LOC_SPEED
                    FROM db_owner.UserInfo WHERE ID='" + user + "' "
                + " and time >= CONVERT(datetime,'" + dtStart.ToString(format) + "')"
                + " and time <= CONVERT(datetime,'" + dtEnd.ToString(format) + "')"
                + " and gps != 7 "
                + " ORDER BY time";
            mPoint.ID = user;


            DBMS.GetDBMS().GetResult(query, mPoint);
            mnv.SetText(query);

        }



        public void UpdatePointsForLocation()
        {
            Points points = new Points();
            DateTime prev = new DateTime();
            double preLat = 0;
            double preLon = 0;
            foreach (Pot pt in mPoint.mPt)
            {
                if (pt.Lat == 0 || pt.Lon == 0 || pt.Lat == -1 || pt.Lon == -1)
                    continue;
                if (preLat == pt.Lat && preLon == pt.Lon)
                    continue;
                /*2012-12-03 cholonge modified
                 * 위의 두 줄을 주석처리하고
                 * 5초 이내의 같은 위치 데이터는 날려버리고
                 * 그 이후 데이터라면 같은 위치 데이터라도 받아들입니다.
                 */
                /*
                if (preLat == pt.Lat && preLon == pt.Lon)
                {
                    dt = pt.Time.Subtract(prev);
                    if (dt.TotalSeconds < 5)
                        continue;
                }
                */
                if (pt.GPS == 1 && prev.Hour == pt.Time.Hour && prev.Minute == pt.Time.Minute)
                {
                    continue;
                }
                
                preLat = pt.Lat;
                preLon = pt.Lon;
                prev = pt.Time;
                pt.CellID = (int)(pt.Lat * 10000) % 10000 * ((int)(pt.Lon * 10000) % 10000);

                points.mPt.Add(pt);

                /////////////forest를 위한 구현
                
            }
            mPoint = points;
        }

        public void PrintVelocity()
        {
            double dist;
            string str;

            for (int i = 1; i < mPoint.mPt.Count; i++)
            {
                dist = Util.GetDistance(mPoint.mPt[i].Lat, mPoint.mPt[i].Lon,
                    mPoint.mPt[i - 1].Lat, mPoint.mPt[i - 1].Lon);

                //double res = Util.GetGap(mPoint.mPt[i].Time, mPoint.mPt[i].Lat, mPoint.mPt[i].Lon);

                //double a = Math.Sin(dlat / 2) * Math.Sin(dlat / 2) + Math.Sin(dlon / 2) *
                //    Math.Sin(dlon / 2) * Math.Cos(lat1) * Math.Cos(lat2);
                //double c = 2 * Math.Atan2(Math.Sqrt(a), Math.Sqrt(1 - a));
                //dist2 = R * c;


                str = "\t(" + mPoint.mPt[i - 1].Lat.ToString("0.0000") +
                    ", " + mPoint.mPt[i - 1].Lon.ToString("0.0000") + ") ("
                    + mPoint.mPt[i].Lat.ToString("0.0000") + ", " +
                    mPoint.mPt[i].Lon.ToString("0.0000") + ")\t" +
                    "d(m): " + (dist * 1000).ToString("0.00")
                    //+ "\t" + (dist2 * 1000).ToString("0.00")
                    + "\ts: " +
                    " (" + mPoint.mPt[i].Time.TimeOfDay.ToString() + ") "
                    + (mPoint.mPt[i].Time - mPoint.mPt[i - 1].Time).TotalSeconds
                    + "\tv(m/s): " + (dist * 1000 / (mPoint.mPt[i].Time - mPoint.mPt[i - 1].Time).TotalSeconds).ToString("0.00")
                    + " (" + mPoint.mPt[i].Speed.ToString("0.00") + ")"
                    + "\t Accuracy: " + mPoint.mPt[i].Accuracy
                    + "\t GPS(" + mPoint.mPt[i].GPS + ") WIFI(" + mPoint.mPt[i].WIFI + ")" ;

                mnv.SetText(""+i++);
            }

        }
        public void GetDistributionGPS()
        {
            double[] coor = {0,0,0,0};
            double[] pre_coor = { 0, 0, 0, 0 };
            Hashtable ht = new Hashtable();
            Stats<double> stat = new Stats<double>();
            DBMS dbm = DBMS.GetDBMS();

            dbm.Request("DISTGPS",null);
            dbm.Connect();
            while(dbm.Next())
            {
                for (int i = 0; i < 4; i++)
                {
                    if (dbm.data[i].ToString() != "")
                        coor[i] = double.Parse(dbm.data[i].ToString());
                    
                }
                if (coor[0] == pre_coor[0] && coor[1] == pre_coor[1]
                        && coor[2] == pre_coor[2] && coor[3] == pre_coor[3])
                    continue;


                double dist = Util.GetDistance(coor[0], coor[1],
                        coor[2], coor[3]);
                if (dist > 10)
                    continue;

                if(ht.Contains(dist.ToString("0.00")))
                {
                    int  cnt = (int)ht[dist.ToString("0.00")];
                    cnt++;
                    ht.Remove(dist.ToString("0.00"));
                    ht.Add(dist.ToString("0.00"),cnt);
                }
                else{
                    ht.Add(dist.ToString("0.00"),1);
                }

                
                for (int i = 0; i < 4; i++)
                {
                    pre_coor[i] = coor[i];
                }
                
                stat.Add(dist);
                mnv.SetText(dist.ToString("0.000"));
            }
            /*
            foreach(DictionaryEntry de in ht)
            {
                mnv.SetText((int)(double.Parse(de.Key.ToString())*100)
                    + "\t" + de.Value.ToString());  
            }
             */
            string str = "Avr : " + stat.GetAvr() + " Stdev : " + stat.GetStdev() ;
            mnv.SetText(str);

        }
        public void CompareDataSet()
        {
           
            Points pt1 = new Points()
                , pt2 = new Points();
            Stat<double> stat;
            DBMS dbm = DBMS.GetDBMS();

            double maxDist = 2, dist;

            dbm.Request("COMPNET", null);
            dbm.Connect();

            while (DBMS.GetDBMS().Next())
            {
                Pot pot = new Pot();
                Pot pot2 = new Pot();

                pot.Time = DateTime.Parse(dbm.data[0].ToString());
                pot2.Time = DateTime.Parse(dbm.data[0].ToString());
                if (dbm.data[1].ToString() != "")
                    pot.Lat = double.Parse(dbm.data[1].ToString());
                if (dbm.data[2].ToString() != "")
                    pot.Lon = double.Parse(dbm.data[2].ToString());
                if (dbm.data[3].ToString() != "")
                    pot.Accuracy = float.Parse(dbm.data[3].ToString());
                if (dbm.data[4].ToString() != "")
                    pot.Speed = float.Parse(dbm.data[4].ToString());

                if (dbm.data[6].ToString() != "")
                    pot2.Lat = double.Parse(dbm.data[6].ToString());
                if (dbm.data[7].ToString() != "")
                    pot2.Lon = double.Parse(dbm.data[7].ToString());
                if (dbm.data[8].ToString() != "")
                    pot2.Accuracy = float.Parse(dbm.data[8].ToString());
                if (dbm.data[9].ToString() != "")
                    pot2.Speed = float.Parse(dbm.data[9].ToString());

                pt1.mPt.Add(pot);
                pt2.mPt.Add(pot2);
            }
            dbm.Close();
            

            stat = new Stat<double>(pt1.mPt.Count);
            for (int i = 0; i < pt1.mPt.Count; i++)
            {
                dist = Util.GetDistance(pt1.mPt[i].Lat, pt1.mPt[i].Lon, pt2.mPt[i].Lat, pt2.mPt[i].Lon);
                if (dist < maxDist)
                    stat.Add(dist);
            }
            double avr = stat.GetAvr(), stdev = stat.GetStdev();
            //1.66 -> 95.05%
            double p95 = 1.66 * stdev + avr;
            string str = "Total test set = " + pt1.mPt.Count + " average : " + (avr * 1000).ToString("0.00")
                + "m    stdev : " + (stdev * 1000).ToString("0.00") + "m    95% : " + (p95 * 1000).ToString("0.00") + "m"
                + "    " + Util.GetDistance(12.31, 11.64, 12.31, 11.64);




            mnv.SetText(str);

        }
        public void MakeHttpRequest()
        {
            map.InitPath();

            foreach (Pot pt in mPoint.mPt)
            {
                if (map.AddPath(pt.Lat, pt.Lon) == false)
                    break;
            }
        }

        public void DrawPoints()
        {

        }

        public string user;
        public StaticMap map;
        private string addon = "";
        public DateTime dtStart;
        public DateTime dtEnd;
        public Points mPoint;
        private Shell shell;
        public Nodes forest;
    }
}
